/******************************************************************************************************
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals settings, Dialog, Dir, FileDialog, print, GroupBox, qsTr, LineEdit, ToolButton, MessageBox, File, dbOpenDatabase, Resumable, ProgressDialog, serialization, DBPlugin, Application, dbMakeDBItems, MnUi*/
/*jslint plusplus: true, indent: 4*/

// Scans a directory recursively for molfiles and related spectra and stores the results in the specified database. 
// For each main file found, optonal files are searched for in same directory as and in all directories below the main file.
function dbImportFilesByLocation() {
	"use strict";

	function getRegExpFiles(aDirName, aRegexp, aGiveErrors) {
		function getRegExpFilesPriv(aDirName, aGiveErrors) {
				//print("getRegExpFilesPriv: " + aDirName);
			var subdirs, i, d, j, entries,
				result = [],
				dir = new Dir(aDirName);
			if (!aDirName || !dir.exists) {
				if (aGiveErrors) {
					MessageBox.critical(qsTr("Directory {0} does not exist.").format(aDirName));
				}
				return result;
			}

			subdirs = dir.entryList("*", Dir.Dirs);
			for (i = 0; i < subdirs.length; i++) {
				d = subdirs[i];
				//print("  subdir: " + d);
				if (d !== "." && d !== "..") {
					result.push(d);
					entries = getRegExpFilesPriv(aDirName + "/" + d, false);
					for (j = 0; j < entries.length; j++) {
						result.push(d + "/" + entries[j]);
					}
				}
			}

			result = result.concat(dir.entryList("*", Dir.Files));
			return result;
		}

		var f, file, result = [], re, files = getRegExpFilesPriv(aDirName, aGiveErrors);

		try {
			re = new RegExp("^" + aRegexp + "$");
		} catch(e) {
			if (aGiveErrors) {
				MessageBox.warning(qsTr("Invalid regular expression."));
			}
			return result;
		}

		files.sort();
		//print(files);
		for (f = 0; f < files.length; f++) {
			file = files[f];
			if (file.match(re)) {
				//print(file + " matches " + re);
				result.push(aDirName + "/" + file);
			}
		}
		if (result.length <= 0 && aGiveErrors) {
			MessageBox.critical(qsTr("Could not find any files matching '{0}' in directory '{1}'.").format(aRegexp, aDirName));
		}
		return result;
	}

	var mainFiles, optFileCount, f, dbname, resumable, progress, startTime, oldFileHistory, mainFileCount, dbDef, m, files,
		optFiles, dw, startTimeDoc, dbItems, cid,
		settingsKey = "Database/Import Files By Location",
		dirSettingsKey = settingsKey + "/Last Directory",
		mainFileIncludesKey = settingsKey + "/Main Files",
		optFileIncludesKey = settingsKey + "/Optional Files",
		optFilesKey = settingsKey + "/Use Optional Files",
		resumeSettingsKey = settingsKey + "/Resume",
		dirName = settings.value(dirSettingsKey, Dir.home()),
		dialog = new Dialog(),
		gbMain = new GroupBox(),
		leDirectory = new LineEdit(),
		tbOpenDir = new ToolButton(),
		leMainFileIncludes = new LineEdit(),
		gbOpt = new GroupBox(),
		leOptFileIncludes = new LineEdit();

	dialog.title = qsTr("Import Files");
	dialog.onOpenDir = function () {
		var dirName = this.text;
		dirName = FileDialog.getExistingDirectory(dirName);
		print("Directory: " + dirName);
		if (dirName) {
			this.text = dirName;
		}
	};

	gbMain.title = qsTr("Main Files");
	dialog.add(gbMain);

	leDirectory.label = qsTr("Base Directory:");
	leDirectory.text = dirName;

	tbOpenDir.text = "...";
	tbOpenDir.clicked.connect(leDirectory, dialog.onOpenDir);
	gbMain.add(leDirectory, tbOpenDir);

	leMainFileIncludes.label = qsTr("Path Mask (RegExp):");
	leMainFileIncludes.text = settings.value(mainFileIncludesKey, ".*\\.mol");
	leMainFileIncludes.toolTip = qsTr("Examples of RegExp:\n.*\\.mol\nPRJ [0-9]{1,4}\\/(fid|1r)");
	gbMain.add(leMainFileIncludes);

	gbOpt.title = qsTr("Optional Files");
	gbOpt.checkable = true;
	gbOpt.checked = settings.value(optFilesKey, false);
	dialog.add(gbOpt);

	leOptFileIncludes.label = qsTr("Path Mask (RegExp):");
	leOptFileIncludes.text = settings.value(optFileIncludesKey, ".*fid");
	leOptFileIncludes.toolTip = "Examples of RegExp:\n.*\\.mol\nPRJ [0-9]{1,4}\\/(fid|1r)";
	gbOpt.add(leOptFileIncludes);

	if (!dialog.exec()) {
		return;
	}

	print("Directory: " + leDirectory.text);
	print("Main files: " + leMainFileIncludes.text);

	settings.setValue(dirSettingsKey, leDirectory.text);
	settings.setValue(mainFileIncludesKey, leMainFileIncludes.text);
	settings.setValue(optFilesKey, gbOpt.checked);
	settings.setValue(optFileIncludesKey, leOptFileIncludes.text);

	// Count main files 
	mainFiles = getRegExpFiles(leDirectory.text, leMainFileIncludes.text, true);
    //print(mainFiles);
	if (mainFiles.length <= 0) {
		return;
	}

	// Count optional files (for error message only)
	if (gbOpt.checked) {
		optFileCount = 0;
		for (f = 0; f < mainFiles.length; ++f) {
			optFileCount += getRegExpFiles(new File(mainFiles[f]).absDirPath, leOptFileIncludes.text, false).length;
		}
		if (optFileCount === 0) {
			MessageBox.critical(qsTr("Could not find any optional files matching '{0}'.").format(leOptFileIncludes.text));
			return;
		}
	}

	// Choose database
	dbname = dbOpenDatabase();
	if (dbname === undefined) {
		return;
	}

	// Show resume dialog
	resumable = new Resumable(resumeSettingsKey, 1, mainFiles.length, "Import Files");
	resumable.dialogMessage = "Found <b>" + mainFiles.length + "</b> main files for import into database <b>" + dbname + "</b>.";
	if (!resumable.init()) {
		return;
	}

	// Show progress dialog
	progress = new ProgressDialog();
	progress.setRange(resumable.minValue - 1, resumable.maxValue);
	progress.show();

	// Process files
	startTime = new Date();
	print("It is now " + startTime.toString());
	oldFileHistory = serialization.fileHistory;
	serialization.fileHistory = false;
	mainFileCount = 0;
	optFileCount = 0;
	dbDef = DBPlugin.client.definition(DBPlugin.client.database);
	for (m = resumable.minValue - 1; m < resumable.maxValue && !progress.wasCanceled; ++m) {
        // Update progress dialog
		progress.value = m;
		progress.labelText = qsTr("Importing file {0} of {1}...\n{2}").format(m - resumable.minValue + 2, resumable.maxValue - resumable.minValue + 1, mainFiles[m]);
        Application.mainWindow.processEvents();

		// Update resumable
		resumable.setValue(m + 1);

		files = [];
		files.push(mainFiles[m]);
		if (gbOpt.checked) {
			optFiles = getRegExpFiles(new File(mainFiles[m]).absDirPath, leOptFileIncludes.text, false);
			for (f = 0; f < optFiles.length; ++f) {
				files.push(optFiles[f]);
			}
		}
		dw = Application.mainWindow.newDocument();
		serialization.open(files);
		print(" Opened ok: " + dw.itemCount() + " items.");
		startTimeDoc = new Date();
        dbItems = dbMakeDBItems(DBPlugin.client, dbDef, true, false);
		cid = DBPlugin.addRecord(DBPlugin.client, dbItems);
		if (cid > 0) {
			print("Saved " +  dbItems.length + " items  to record " + cid + " in " + ((new Date() - startTimeDoc) / 1000) + " seconds.");
			mainFileCount++;
			optFileCount += files.length - 1;
		} else {
			MessageBox.critical(qsTr("Error while saving."));
		}
		dw.close();
	}
	if (!progress.wasCanceled) {
		resumable.setValue(0);
	}
	serialization.fileHistory = oldFileHistory;
    progress.close();
	MessageBox.information(qsTr("Imported <b>{0}</b> main files and <b>{1}</b> optional files into database <b>{2}</b>.").format(mainFileCount, optFileCount, dbname));
	print("All done in " + ((new Date() - startTime) / 1000) + " seconds.");
}

if (this.MnUi && MnUi.scripts_db) {
	MnUi.scripts_db.scripts_db_ImportFilesByLocation = dbImportFilesByLocation;
}
